library(readr)
library(tidyverse)
library(forcats)
library(plotly)
library(knitr, warn.conflicts = FALSE, quietly=TRUE)
library(RColorBrewer)
library(stringr)
library(dygraphs)
library(xts)
myPalette <- brewer.pal(8, "YlGn")
vgsales <- read_csv("vgsales.csv")
Rows: 16598 Columns: 11
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): Name, Platform, Year, Genre, Publisher
dbl (6): Rank, NA_Sales, EU_Sales, JP_Sales, Other_Sales, Global_Sales
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
WorldPopulation <- read.csv("H:/Hochschule/VDA/R_Studio_Default_workspace/API_SP.POP.TOTL_DS2_en_csv_v2_4218816.csv")
Das verwendete Dataset des Projekts: https://www.kaggle.com/datasets/gregorut/videogamesales
Dieses Dataset umfasst verschiedene Daten zu Videogamereleases und
Sales zwischen 1980 und 2016.
Ideen/Statements:
Bestimmte Entwickler/Publisher häufen sich (Nintendo/EA) Ältere
Plattformen/spiele haben mehr verkäufe bzw Wie hat sich die Anzahl der
verkäufe im laufe der jahre entwickelt? Genrenentwicklung über die Jahre
Welche Spiele/Publisher/Genres in welchen Teilen der welt sich häufen
(Nintendo in Asien, Shooter in US/EU) Gibt es Statistische zusammenhänge
zwischen einzelnen Faktoren e.g. Genre -> Sales Welche Jahre sind die
besten in der Anzahl der releasten games und hängt dies mit den Sales
zusammen? (je mehr Total Sales desto mehr Games verkaufen sich) Welche
Jahre sind die besten in Anzahl Sales pro game (neuer = besser?) Welche
Plattform ist die beste und unterscheidet sich diese nach Region? Gibt
es Unterschiede in den Regionen/hängt das mit der Anzahl der Einwohner
der Region zusammen? (Asia>US>EU)
Zuerst schauen wir und die Anzahl der Videospiele und die Anzahl der
Verkäufe im laufe der Jahre an.
Hierzu verwenden wir Liniendiagramme. Außerdem filtern wir alle
Datensätze in denen kein Jahr angegeben ist sowie Datensätze mit den
Jahren 2017 und 2020 um Fehlerhafte Daten und unvollständige Daten aus
der Liste zu entfernen.
grouped <- vgsales %>%
group_by(Year) %>%
dplyr::summarize(Anzahl =n()) %>% filter(Year!='N/A')%>%filter(Year!=2020) %>% filter(Year!='2017') %>%
as.data.frame()
filtered <- grouped %>% select(Year,Anzahl)
ax <- list(
title = "Year"
)
ay <- list(
title = "Amount"
)
filtered %>%
plot_ly(x = ~Year, y = ~Anzahl, type = 'scatter', mode = 'lines', fill = 'tozeroy') %>%
layout(title="Game Amount from 1980-2016",
xaxis = ax,
yaxis = ay
)
NA
grouped <- vgsales %>%
group_by(Year) %>%
dplyr::summarize(gr_sum = sum(Global_Sales)) %>% filter(Year!='N/A')%>%filter(Year!=2020) %>% filter(Year!='2017') %>%
as.data.frame()
filtered <- grouped %>% select(Year,gr_sum)
ax <- list(
title = "Year"
)
ay <- list(
title = "Sales Per Game (in mio)"
)
filtered %>%
plot_ly(x = ~Year, y = ~gr_sum, type = 'scatter', mode = 'lines', fill = 'tozeroy') %>%
layout(title="Sales per Game from 1980-2016",
xaxis = ax,
yaxis = ay
)
NA
grouped <- vgsales %>%
group_by(Year) %>%
dplyr::summarize(gr_sum = sum(Global_Sales)/n()) %>% filter(Year!='N/A')%>%filter(Year!=2020) %>% filter(Year!='2017') %>%
as.data.frame()
filtered <- grouped %>% select(Year,gr_sum)
ax <- list(
title = "Year"
)
ay <- list(
title = "Sales per Year(in mio)"
)
filtered %>%
plot_ly(x = ~Year, y = ~gr_sum, type = 'scatter', mode = 'lines', fill = 'tozeroy') %>%
layout(title="Sales per Game from 1980-2016",
xaxis = ax,
yaxis = ay
)
NA
Hier erkennen wir das 2008 und 2009 die Jahre waren in denen die
Meisten Games Releast wurden und diese auch die meisten Verkäufe haben.
Den größten per Game Verkaufswert gab es allerdings 1984,1985 und 1989.
Neuere spiele hingegen verkaufen sich durchschnittlich schlechter was
durch das größere Angebot auch zu erwarten ist.
Nun betrachten wir die Anzahl der Videospiele aufgelistet nach
Platform.
Hierbei stellt sich die Frage ob ältere Plattformen mehr
Spielereleases haben wovon auszugehen ist. Hierzu verwenden wir ein
einfaches Balkendiagramm welche eine gute erste übersicht bietet.
grouped <- vgsales %>%
group_by(Platform) %>%
summarize(Anzahl =n())
ordered <- grouped[order(grouped$Anzahl), decreasing = FALSE]
ordered$Platform <- as_factor(ordered$Platform)
ax <- list(
title = "Publisher"
)
ay <- list(
title = "Anzahl"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Platform,Anzahl, .desc="true"),
y=~Anzahl,
name="Game Amount by Platform") %>%
layout(title="Game Amount by Platform",
xaxis = ax,
yaxis = ay
)
Dies lässt sich nicht generell bestätigen aber ein Trend ist
definitiv erkennbar.
Nun stellt sich die Frage welche Plattform die meisten Sales hat.
grouped <- vgsales %>%
group_by(Platform) %>%
summarize(sum(Global_Sales)) %>%
rename(
Global_Sales = "sum(Global_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Platform <- as_factor(ordered$Platform)
ax <- list(
title = "Platform"
)
ay <- list(
title = "Global Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Platform,Global_Sales, .desc="true"),
y=~Global_Sales,
name="Sales Amount by Platform") %>%
layout(title="Sales Amount by Platform",
xaxis = ax,
yaxis = ay
)
Wie sich herausstellt ist dies jedoch nicht die Platform welches die
meisten Gamereleases hat.
Nun analzsieren wir die unterschiede der Regionen.
Hierzu verwenden wir sowohl sorted bar plots sowie um einen besseren
Überblick über die Prozentualverteilung der Konsolen in den einzelnen
Regionen Pie charts.
Einzuwenden hierbei ist, dass die Regionen natürlich unterschiedlich
viele Einwohner haben.Ein vergleich der absoluten Saleswerte ist hierbei
natürlich nur wenig ausschlaggebend zeigt aber einen generellen
beliebtheitstrend der Konsolen auf.
grouped <- vgsales %>%
group_by(Platform) %>%
summarize(sum(EU_Sales)) %>%
rename(
Global_Sales = "sum(EU_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Platform <- as_factor(ordered$Platform)
ax <- list(
title = "Platform"
)
ay <- list(
title = "EU Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Platform,Global_Sales, .desc="true"),
y=~Global_Sales,
name="EU Sales Amount by Platform") %>%
layout(title="EU Sales Amount by Platform",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Platform,textinfo='label+percent',
name="EU Sales Amount by Publisher") %>%
layout(title="EU Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Platform) %>%
summarize(sum(NA_Sales)) %>%
rename(
Global_Sales = "sum(NA_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Platform <- as_factor(ordered$Platform)
ax <- list(
title = "Platform"
)
ay <- list(
title = "NA Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Platform,Global_Sales, .desc="true"),
y=~Global_Sales,
name="NA Sales Amount by Platform") %>%
layout(title="NA Sales Amount by Platform",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Platform,textinfo='label+percent',
name="NA Sales Amount by Publisher") %>%
layout(title="NA Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Platform) %>%
summarize(sum(JP_Sales)) %>%
rename(
Global_Sales = "sum(JP_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Platform <- as_factor(ordered$Platform)
ax <- list(
title = "Platform"
)
ay <- list(
title = "JP Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Platform,Global_Sales, .desc="true"),
y=~Global_Sales,
name="JP Sales Amount by Platform") %>%
layout(title="JP Sales Amount by Platform",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Platform,textinfo='label+percent',
name="JP Sales Amount by Platform") %>%
layout(title="JP Sales Amount by Platform",
xaxis = ax,
yaxis = ay
)
Im genensatz zur EU, in der das japanische unternehmen Sony mit der
PS2 und PS3 die liste anführt, hat in den USA das Landeseigene
softwareunternehmen Microsoft mit der Xbox360 die Nase vorn. In Japan
hingegen ist wie zu erwarten der japanische hersteller Nintendo mit dem
DS der Markführer.
Um sich das Ganze etwas genauer anzuschauen betrachten wir die Anzahl
der Sales per Platform im Verlauf der Jahre.
Um eine überladung des Diagramms zu verhindern werden hier allerdings
nur Plattformen mit mindestens 60 mio in Sales im entsprechenden Jahr
berücksichtigt. Dies hat den Nachteil das einige z.T wichtige Daten
Fehlen, ein Weglassen ebenjenes Filters fürt aber zu kompletter
Unübersichtlichkeit.
`summarise()` has grouped output by 'Year'. You can override using the `.groups` argument.
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Hier erkennen wir das Platform, wie zu erwarten, meist kurz nach
Release die größten Verkaufszahlen verzeichnen.
Nun stellt sich die Frage ob sich neben bestimmten Platformen auch
bestimmte Entwickler/Publisher häufen. Hierbei gehen wir davon aus das
vermutlich Nintendo und EA die Liste anführen. Hierzu verwenden wir
wiederum sorted Bar-Charts und kürzen die Namen um die Begriffe
“Entertainment”, “Interactive”, “Game”, “Games” und “Studios” da dies
die Namen nur unnötig verlängert und Filtern Publisher mit Geringen
Anzahl an Game Releases.
grouped <- vgsales %>%
group_by(Publisher) %>%
summarize(Anzahl =n()) %>%
filter(Anzahl>100) %>% filter(Publisher!="Unknown")
ordered <- grouped[order(grouped$Anzahl), decreasing = FALSE]
ordered$Publisher <-str_remove_all(ordered$Publisher, "Entertainment")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Interactive")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Studios")
ordered$Publisher <- as_factor(ordered$Publisher)
ax <- list(
title = "Publisher"
)
ay <- list(
title = "Anzahl"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Publisher,Anzahl, .desc="true"),
y=~Anzahl,
name="Game Amount by Publisher") %>%
layout(title="Game Amount by Publisher",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Publisher) %>%
summarize(Anzahl =n(),sum(Global_Sales)) %>%
filter(Anzahl>100) %>%
rename(
Global_Sales = "sum(Global_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Publisher <-str_remove_all(ordered$Publisher, "Entertainment")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Interactive")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Studios")
ordered$Publisher <- as_factor(ordered$Publisher)
ax <- list(
title = "Publisher"
)
ay <- list(
title = "Global Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Publisher,Global_Sales, .desc="true"),
y=~Global_Sales,
name="Sales Amount by Publisher") %>%
layout(title="Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
Auffällig ist hier die diskrepanz zwischen Anzahl der Spielereleases
und Anzahl der Spieleverkäufe. Im gegensatz zu der Anzahl der Spiele
(bei dem Nintendo nur auf platz 6 Sitz) dominiert Nintendo im anzahl der
Sales.
Nun stellt sich wieder einmal die Frage ob sich dies in Bestimmten
teilen der Welt unterscheidet und hierzu verwenden wir wiederum die
SortedBar/Piechart kombo und die bereits genannten Filter
grouped <- vgsales %>%
group_by(Publisher) %>%
summarize(Anzahl =n(),sum(EU_Sales)) %>%
filter(Anzahl>100) %>%
rename(
Global_Sales = "sum(EU_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Publisher <-str_remove_all(ordered$Publisher, "Entertainment")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Interactive")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Studios")
ordered$Publisher <- as_factor(ordered$Publisher)
ax <- list(
title = "Publisher"
)
ay <- list(
title = "EU Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Publisher,Global_Sales, .desc="true"),
y=~Global_Sales,
name="EU Sales Amount by Publisher") %>%
layout(title="EU Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Publisher,
name="EU Sales Amount by Publisher") %>%
layout(title="EU Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Publisher) %>%
summarize(Anzahl =n(),sum(NA_Sales)) %>%
filter(Anzahl>100) %>%
rename(
Global_Sales = "sum(NA_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Publisher <-str_remove_all(ordered$Publisher, "Entertainment")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Interactive")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Studios")
ordered$Publisher <- as_factor(ordered$Publisher)
ax <- list(
title = "Publisher"
)
ay <- list(
title = "NA Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Publisher,Global_Sales, .desc="true"),
y=~Global_Sales,
name="NA Sales Amount by Publisher") %>%
layout(title="NA Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Publisher,textinfo='label+percent',
name="NA Sales Amount by Publisher") %>%
layout(title="NA Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Publisher) %>%
summarize(Anzahl =n(),sum(JP_Sales)) %>%
filter(Anzahl>100) %>%
rename(
Global_Sales = "sum(JP_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ordered$Publisher <-str_remove_all(ordered$Publisher, "Entertainment")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Interactive")
ordered$Publisher <-str_remove_all(ordered$Publisher, "Studios")
ordered$Publisher <- as_factor(ordered$Publisher)
ax <- list(
title = "Publisher"
)
ay <- list(
title = "JP Sales (in mio)"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Publisher,Global_Sales, .desc="true"),
y=~Global_Sales,
name="JP Sales Amount by Publisher") %>%
layout(title="JP Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Publisher,
name="JP Sales Amount by Publisher") %>%
layout(title="JP Sales Amount by Publisher",
xaxis = ax,
yaxis = ay
)
Zwischen EU und US lassen sich hier kaum Unterschiede feststellen in
Japan hingegen ist eine verschiebung zu erkennen. Japanische Publisher
führen hierbei die Liste an und drängen andere große unternehmen von den
Top spots.
Nun schauen wir uns die Genreverteilung von Videospielen an. Hierzu
verwenden wir wiederum die Altbekannte sorted Bar/Pie-Chart kombo.
grouped <- vgsales %>%
group_by(Genre) %>%
summarize(Anzahl =n())
grouped$Anzahl<-as_vector(grouped$Anzahl)
ordered <- grouped[order(grouped$Anzahl), decreasing = FALSE]
ordered$Genre <- as_factor(ordered$Genre)
ax <- list(
title = "Genre"
)
ay <- list(
title = "Anzahl"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Genre,Anzahl, .desc="true"),
y=~Anzahl,
name="Amount by Genre") %>%
layout(title="Amount by Genre",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Anzahl,labels=~Genre,
name="Amount by Genre") %>%
layout(title="Amount by Genre",
xaxis = ax,
yaxis = ay
)
Hierbei ist zu erkennen das Action und Sports ein Großteil (34%) der
Genres ausmachen. Die Frage ist jedoch wie sind die Verkäufe verteilt
und beeinflusst die anzahl der Games pro Genre irgendwie die
Verkaufszahlen?
grouped <- vgsales %>%
group_by(Genre) %>%
summarize(sum(Global_Sales)) %>%
rename(
Global_Sales = "sum(Global_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ax <- list(
title = "Genre"
)
ay <- list(
title = "Sales"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Genre,Global_Sales, .desc="true"),
y=~Global_Sales,
name="Sales by Genre") %>%
layout(title="Sales by Genre",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Genre,
name="Sales by Genre") %>%
layout(title="Sales by Genre",
xaxis = ax,
yaxis = ay
)
Hierbei erkennen wir das es einige Unterschiede gibt Action und
sports machen jedoch weiterhin einen Grosteil des Markts aus.
Nun schauen wir uns die Unterscheide in den Regionen an.
grouped <- vgsales %>%
group_by(Genre) %>%
summarize(sum(EU_Sales)) %>%
rename(
Global_Sales = "sum(EU_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ax <- list(
title = "Genre"
)
ay <- list(
title = "Sales"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Genre,Global_Sales, .desc="true"),
y=~Global_Sales,
name="Sales by Genre (EU)") %>%
layout(title="Sales by Genre (EU)",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Genre,
name="Sales by Genre (EU)") %>%
layout(title="Sales by Genre (EU)",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Genre) %>%
summarize(sum(NA_Sales)) %>%
rename(
Global_Sales = "sum(NA_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ax <- list(
title = "Genre"
)
ay <- list(
title = "Sales"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Genre,Global_Sales, .desc="true"),
y=~Global_Sales,
name="Sales by Genre (NA)") %>%
layout(title="Sales by Genre (NA)",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Genre,
name="Sales by Genre (NA)") %>%
layout(title="Sales by Genre (NA)",
xaxis = ax,
yaxis = ay
)
grouped <- vgsales %>%
group_by(Genre) %>%
summarize(sum(JP_Sales)) %>%
rename(
Global_Sales = "sum(JP_Sales)"
)
grouped$Global_Sales<-as_vector(grouped$Global_Sales)
ordered <- grouped[order(grouped$Global_Sales), decreasing = FALSE]
ax <- list(
title = "Genre"
)
ay <- list(
title = "Sales"
)
ordered%>%
plot_ly() %>%
add_bars(x=~fct_reorder(Genre,Global_Sales, .desc="true"),
y=~Global_Sales,
name="Sales by Genre (JP)") %>%
layout(title="Sales by Genre (JP)",
xaxis = ax,
yaxis = ay
)
ordered%>%
plot_ly() %>%
add_pie(values =~Global_Sales,labels=~Genre,
name="Sales by Genre (JP)") %>%
layout(title="Sales by Genre (JP)",
xaxis = ax,
yaxis = ay
)
Hierbei erkennen wir wieder einmal das US und EU recht ähnlich sind
wohingegen Japan ein gänzlich anderes Genreshema erkennen lässt. In
Japan dominiert Role-Playing welches sich in EU und US nur auf platz 7
befindet.
Nun schauen wir uns die Genreentwicklung über die Jahre an. Hierzu
verwenden wir LinePlots.
grouped <- vgsales %>%
group_by(Year, Genre) %>%
dplyr::summarize(Anzahl =n()) %>% filter(Year!='N/A')%>%filter(Year!=2020) %>% filter(Year!='2017') %>%
as.data.frame()
`summarise()` has grouped output by 'Year'. You can override using the `.groups` argument.
filtered <- grouped %>% select(Year,Genre,Anzahl)
ax <- list(
title = "Year"
)
ay <- list(
title = "Anzahl"
)
filtered %>%
plot_ly() %>%
add_lines(x=~Year,
y=~Anzahl, color=~Genre)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
filtered %>%
plot_ly(x = ~Year, y = ~Anzahl, type = 'scatter', mode = 'none', fill = 'tozeroy',color = ~Genre)%>%
layout(title="Amount by Genre from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
filtered %>%
plot_ly(x = ~Year, y = ~Anzahl, type = 'scatter', mode = 'none', stackgroup = 'one',color = ~Genre)%>%
layout(title="Amount by Genre from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
ay <- list(
title = "Percent %"
)
filtered %>%
plot_ly(x = ~Year, y = ~Anzahl, type = 'scatter', mode = 'none', stackgroup = 'one',groupnorm = 'percent',color = ~Genre)%>%
layout(title="Marketamount genreshift in % from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Schauen wir uns an wie sich die verkäufe entwickelt haben.
grouped <- vgsales %>%
group_by(Year, Genre) %>%
dplyr::summarize(gr_sum = sum(Global_Sales)) %>% filter(Year!='N/A')%>%filter(Year!=2020) %>% filter(Year!='2017') %>%
as.data.frame()
`summarise()` has grouped output by 'Year'. You can override using the `.groups` argument.
filtered <- grouped %>% select(Year,Genre,gr_sum)
ax <- list(
title = "Year"
)
ay <- list(
title = "Global_Sales"
)
filtered %>%
plot_ly() %>%
add_lines(x=~Year,
y=~gr_sum, color=~Genre) %>%
layout(title="Sales by Genre from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
filtered %>%
plot_ly(x = ~Year, y = ~gr_sum, type = 'scatter', mode = 'none', fill = 'tozeroy',color = ~Genre) %>%
layout(title="Sales by Genre from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
filtered %>%
plot_ly(x = ~Year, y = ~gr_sum, type = 'scatter', mode = 'none', stackgroup = 'one',color = ~Genre)%>%
layout(title="Sales by Genre from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
ay <- list(
title = "Percent %"
)
filtered %>%
plot_ly(x = ~Year, y = ~gr_sum, type = 'scatter', mode = 'none', stackgroup = 'one',groupnorm = 'percent',color = ~Genre)%>%
layout(title="Marketshare genreshift in % from 1980-2016",
xaxis = ax,
yaxis = ay
)
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Nun stellt sich die Frage hab sich die Verkäufe ähnlich der anzahl
der GameReleases entwickelt?
`summarise()` has grouped output by 'Year'. You can override using the `.groups` argument.
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Wie sieht es mit Genres pro publisher aus?
Hierzu verwenden wir ein stacked Bar-Plot. Dazu filtern wir Genres
von Publishern mit mindestens 50 mio in Sales. Dies entfernt natürlich
einiges an Information allerdings geht sonst einiges an
Übersichtlichkeit verloren. Zusätzlich werden erneut die Worte
“Entertainment”, “Interactive”, “Game”, “Games” und “Studios”
entfernt.
`summarise()` has grouped output by 'Publisher'. You can override using the `.groups` argument.
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2") :
n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Wie sieht es mit den Pro kopf Sales Global und pro Region aus?
Error in eval(expr, data, expr_env) : object 'Genre' not found
LS0tDQp0aXRsZTogIlZEQSBQcm9qZWt0Ig0Kb3V0cHV0OiANCiAgIGh0bWxfZG9jdW1lbnQgOiANCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgIGh0bWxfbm90ZWJvb2sgOiANCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgIA0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShmb3JjYXRzKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGtuaXRyLCB3YXJuLmNvbmZsaWN0cyA9IEZBTFNFLCBxdWlldGx5PVRSVUUpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkoZHlncmFwaHMpDQpsaWJyYXJ5KHh0cykNCm15UGFsZXR0ZSA8LSBicmV3ZXIucGFsKDgsICJZbEduIikNCnZnc2FsZXMgPC0gcmVhZF9jc3YoInZnc2FsZXMuY3N2IikNCldvcmxkUG9wdWxhdGlvbiA8LSByZWFkLmNzdigiSDovSG9jaHNjaHVsZS9WREEvUl9TdHVkaW9fRGVmYXVsdF93b3Jrc3BhY2UvQVBJX1NQLlBPUC5UT1RMX0RTMl9lbl9jc3ZfdjJfNDIxODgxNi5jc3YiKQ0KYGBgDQpEYXMgdmVyd2VuZGV0ZSBEYXRhc2V0IGRlcyBQcm9qZWt0czogaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9ncmVnb3J1dC92aWRlb2dhbWVzYWxlcw0KDQpEaWVzZXMgRGF0YXNldCB1bWZhc3N0IHZlcnNjaGllZGVuZSBEYXRlbiB6dSBWaWRlb2dhbWVyZWxlYXNlcyB1bmQgU2FsZXMgendpc2NoZW4gMTk4MCB1bmQgMjAxNi4NCg0KSWRlZW4vU3RhdGVtZW50czoNCg0KDQpCZXN0aW1tdGUgRW50d2lja2xlci9QdWJsaXNoZXIgaMOkdWZlbiBzaWNoIChOaW50ZW5kby9FQSkNCsOEbHRlcmUgUGxhdHRmb3JtZW4vc3BpZWxlIGhhYmVuIG1laHIgdmVya8OkdWZlIGJ6dyBXaWUgaGF0IHNpY2ggZGllIEFuemFobCBkZXIgdmVya8OkdWZlIGltIGxhdWZlIGRlciBqYWhyZSBlbnR3aWNrZWx0Pw0KR2VucmVuZW50d2lja2x1bmcgw7xiZXIgZGllIEphaHJlDQpXZWxjaGUgU3BpZWxlL1B1Ymxpc2hlci9HZW5yZXMgaW4gd2VsY2hlbiBUZWlsZW4gZGVyIHdlbHQgc2ljaCBow6R1ZmVuIChOaW50ZW5kbyBpbiBBc2llbiwgU2hvb3RlciBpbiBVUy9FVSkNCkdpYnQgZXMgU3RhdGlzdGlzY2hlIHp1c2FtbWVuaMOkbmdlIHp3aXNjaGVuIGVpbnplbG5lbiBGYWt0b3JlbiBlLmcuIEdlbnJlIC0+IFNhbGVzDQpXZWxjaGUgSmFocmUgc2luZCBkaWUgYmVzdGVuIGluIGRlciBBbnphaGwgZGVyIHJlbGVhc3RlbiBnYW1lcyB1bmQgaMOkbmd0IGRpZXMgbWl0IGRlbiBTYWxlcyB6dXNhbW1lbj8gKGplIG1laHIgVG90YWwgU2FsZXMgZGVzdG8gbWVociBHYW1lcyB2ZXJrYXVmZW4gc2ljaCkNCldlbGNoZSBKYWhyZSBzaW5kIGRpZSBiZXN0ZW4gaW4gQW56YWhsIFNhbGVzIHBybyBnYW1lIChuZXVlciA9IGJlc3Nlcj8pDQpXZWxjaGUgUGxhdHRmb3JtIGlzdCBkaWUgYmVzdGUgdW5kIHVudGVyc2NoZWlkZXQgc2ljaCBkaWVzZSBuYWNoIFJlZ2lvbj8NCkdpYnQgZXMgVW50ZXJzY2hpZWRlIGluIGRlbiBSZWdpb25lbi9ow6RuZ3QgZGFzIG1pdCBkZXIgQW56YWhsIGRlciBFaW53b2huZXIgZGVyIFJlZ2lvbiB6dXNhbW1lbj8gKEFzaWE+VVM+RVUpDQoNCg0KDQpadWVyc3Qgc2NoYXVlbiB3aXIgdW5kIGRpZSBBbnphaGwgZGVyIFZpZGVvc3BpZWxlIHVuZCBkaWUgQW56YWhsIGRlciBWZXJrw6R1ZmUgaW0gbGF1ZmUgZGVyIEphaHJlIGFuLg0KDQpIaWVyenUgdmVyd2VuZGVuIHdpciBMaW5pZW5kaWFncmFtbWUuIEF1w59lcmRlbSBmaWx0ZXJuIHdpciBhbGxlIERhdGVuc8OkdHplIGluIGRlbmVuIGtlaW4gSmFociBhbmdlZ2ViZW4gaXN0IHNvd2llIERhdGVuc8OkdHplIG1pdCBkZW4gSmFocmVuIDIwMTcgdW5kIDIwMjAgdW0gRmVobGVyaGFmdGUgRGF0ZW4gdW5kIHVudm9sbHN0w6RuZGlnZSBEYXRlbiBhdXMgZGVyIExpc3RlIHp1IGVudGZlcm5lbi4NCg0KDQpgYGB7ciBwbG90KEFtb3VudEJ5WWVhciksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQoNCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGdyb3VwX2J5KFllYXIpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKEFuemFobCA9bigpKSAlPiUgZmlsdGVyKFllYXIhPSdOL0EnKSU+JWZpbHRlcihZZWFyIT0yMDIwKSAlPiUgZmlsdGVyKFllYXIhPScyMDE3JykgJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KDQoNCmZpbHRlcmVkIDwtIGdyb3VwZWQgJT4lIHNlbGVjdChZZWFyLEFuemFobCkNCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiWWVhciINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiQW1vdW50Ig0KDQopDQoNCmZpbHRlcmVkICU+JQ0KcGxvdF9seSh4ID0gflllYXIsIHkgPSB+QW56YWhsLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgZmlsbCA9ICd0b3plcm95JykgJT4lIA0KICBsYXlvdXQodGl0bGU9IkdhbWUgQW1vdW50IGZyb20gMTk4MC0yMDE2IiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQoNCmBgYA0KDQpgYGB7ciBwbG90KEdhbWVTYWxlc0J5WWVhciksIGluY2x1ZGU9VFJVRSwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCg0KZ3JvdXBlZCA8LSB2Z3NhbGVzICAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgZ3JvdXBfYnkoWWVhcikgJT4lDQogIGRwbHlyOjpzdW1tYXJpemUoZ3Jfc3VtID0gc3VtKEdsb2JhbF9TYWxlcykpICU+JSBmaWx0ZXIoWWVhciE9J04vQScpJT4lZmlsdGVyKFllYXIhPTIwMjApICU+JSBmaWx0ZXIoWWVhciE9JzIwMTcnKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQoNCg0KZmlsdGVyZWQgPC0gZ3JvdXBlZCAlPiUgc2VsZWN0KFllYXIsZ3Jfc3VtKQ0KDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJZZWFyIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJTYWxlcyBQZXIgR2FtZSAoaW4gbWlvKSINCg0KKQ0KDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gfmdyX3N1bSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIGZpbGwgPSAndG96ZXJveScpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBwZXIgR2FtZSBmcm9tIDE5ODAtMjAxNiIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KDQpgYGANCg0KYGBge3IgcGxvdChTYWxlc2J5R2FtZUJ5WWVhciksIGluY2x1ZGU9VFJVRSwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCg0KZ3JvdXBlZCA8LSB2Z3NhbGVzICAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgZ3JvdXBfYnkoWWVhcikgJT4lDQogIGRwbHlyOjpzdW1tYXJpemUoZ3Jfc3VtID0gc3VtKEdsb2JhbF9TYWxlcykvbigpKSAlPiUgZmlsdGVyKFllYXIhPSdOL0EnKSU+JWZpbHRlcihZZWFyIT0yMDIwKSAlPiUgZmlsdGVyKFllYXIhPScyMDE3JykgJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KDQoNCmZpbHRlcmVkIDwtIGdyb3VwZWQgJT4lIHNlbGVjdChZZWFyLGdyX3N1bSkNCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiWWVhciINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiU2FsZXMgcGVyIEdhbWUiDQoNCikNCg0KZmlsdGVyZWQgJT4lDQpwbG90X2x5KHggPSB+WWVhciwgeSA9IH5ncl9zdW0sIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCBmaWxsID0gJ3RvemVyb3knKSAlPiUgDQogIGxheW91dCh0aXRsZT0iU2FsZXMgcGVyIEdhbWUgZnJvbSAxOTgwLTIwMTYiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCg0KYGBgDQpIaWVyIGVya2VubmVuIHdpciBkYXMgMjAwOCB1bmQgMjAwOSBkaWUgSmFocmUgd2FyZW4gaW4gZGVuZW4gZGllIE1laXN0ZW4gR2FtZXMgUmVsZWFzdCB3dXJkZW4gdW5kIGRpZXNlIGF1Y2ggZGllIG1laXN0ZW4gVmVya8OkdWZlIGhhYmVuLg0KRGVuIGdyw7bDn3RlbiBwZXIgR2FtZSBWZXJrYXVmc3dlcnQgZ2FiIGVzIGFsbGVyZGluZ3MgMTk4NCwxOTg1IHVuZCAxOTg5LiBOZXVlcmUgc3BpZWxlIGhpbmdlZ2VuIHZlcmthdWZlbiBzaWNoIGR1cmNoc2Nobml0dGxpY2ggc2NobGVjaHRlciB3YXMgZHVyY2ggZGFzIGdyw7bDn2VyZSBBbmdlYm90IGF1Y2ggenUgZXJ3YXJ0ZW4gaXN0Lg0KDQpOdW4gYmV0cmFjaHRlbiB3aXIgZGllIEFuemFobCBkZXIgVmlkZW9zcGllbGUgYXVmZ2VsaXN0ZXQgbmFjaCBQbGF0Zm9ybS4NCmBgYHtyIG5vcGxvdCwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIGluY2x1ZGUgPUZBTFNFLH0NCnZnc2FsZXMgJT4lIA0KICBwbG90X2x5KA0KICAgIHg9flBsYXRmb3JtLA0KICAgIHN0cm9rZT1JKCJibGFjayIpLA0KICAgIG5hbWU9IkFtb3VudCBieSBQbGF0Zm9ybSIpICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGU9IkFtb3VudCBieSBQbGF0Zm9ybSIpDQp2Z3NhbGVzICU+JSANCiAgcGxvdF9seSAlPiUgDQogIGFkZF9ib3hwbG90KA0KICAgIHg9flBsYXRmb3JtLA0KICAgIHN0cm9rZT1JKCJibGFjayIpLA0KICAgIG5hbWU9IkFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KA0KICAgIHRpdGxlPSJBbW91bnQgYnkgUGxhdGZvcm0iKQ0KDQp2Z3NhbGVzICU+JSANCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoDQogICAgeD1+R2xvYmFsX1NhbGVzLA0KICAgIHk9flBsYXRmb3JtLA0KICAgIG5hbWU9IlNhbGVzIGJ5IFBsYXRmb3JtIChpbiBtaW8pIikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGU9IlNhbGVzIGJ5IFBsYXRmb3JtIChpbiBtaW8pIikNCg0KYGBgDQpIaWVyYmVpIHN0ZWxsdCBzaWNoIGRpZSBGcmFnZSBvYiDDpGx0ZXJlIFBsYXR0Zm9ybWVuIG1laHIgU3BpZWxlcmVsZWFzZXMgaGFiZW4gd292b24gYXVzenVnZWhlbiBpc3QuDQpIaWVyenUgdmVyd2VuZGVuIHdpciBlaW4gZWluZmFjaGVzIEJhbGtlbmRpYWdyYW1tIHdlbGNoZSBlaW5lIGd1dGUgZXJzdGUgw7xiZXJzaWNodCBiaWV0ZXQuDQpgYGB7ciBwbG90LCBlY2hvID0gVFJVRSxtZXNzYWdlPUZBTFNFLHJlc3VsdHM9J21hcmt1cCcsfQ0KZ3JvdXBlZCA8LSB2Z3NhbGVzICAlPiUgDQogIGdyb3VwX2J5KFBsYXRmb3JtKSAlPiUgDQogIHN1bW1hcml6ZShBbnphaGwgPW4oKSkgDQoNCm9yZGVyZWQgPC0gZ3JvdXBlZFtvcmRlcihncm91cGVkJEFuemFobCksIGRlY3JlYXNpbmcgPSBGQUxTRV0NCm9yZGVyZWQkUGxhdGZvcm0gPC0gYXNfZmFjdG9yKG9yZGVyZWQkUGxhdGZvcm0pDQoNCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiUHVibGlzaGVyIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJBbnphaGwiDQopDQpvcmRlcmVkJT4lDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF9iYXJzKHg9fmZjdF9yZW9yZGVyKFBsYXRmb3JtLEFuemFobCwgLmRlc2M9InRydWUiKSwNCiAgICAgICAgICAgeT1+QW56YWhsLA0KICAgICAgICAgICBuYW1lPSJHYW1lIEFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJHYW1lIEFtb3VudCBieSBQbGF0Zm9ybSIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgDQogICAgICAgICApDQpgYGANCkRpZXMgbMOkc3N0IHNpY2ggbmljaHQgZ2VuZXJlbGwgYmVzdMOkdGlnZW4gYWJlciBlaW4gVHJlbmQgaXN0IGRlZmluaXRpdiBlcmtlbm5iYXIuDQoNCg0KTnVuIHN0ZWxsdCBzaWNoIGRpZSBGcmFnZSB3ZWxjaGUgUGxhdHRmb3JtIGRpZSBtZWlzdGVuIFNhbGVzIGhhdC4NCg0KYGBge3IgcGxvdChQbGF0Zm9ybVJhbmtpbmdfR2xvYmFsKSwgZWNobyA9IFRSVUUsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdtYXJrdXAnLH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQbGF0Zm9ybSkgJT4lIA0KICBzdW1tYXJpemUoc3VtKEdsb2JhbF9TYWxlcykpICAlPiUNCnJlbmFtZSgNCiAgICBHbG9iYWxfU2FsZXMgPSAic3VtKEdsb2JhbF9TYWxlcykiDQogICAgKQ0KZ3JvdXBlZCRHbG9iYWxfU2FsZXM8LWFzX3ZlY3Rvcihncm91cGVkJEdsb2JhbF9TYWxlcykNCm9yZGVyZWQgPC0gZ3JvdXBlZFtvcmRlcihncm91cGVkJEdsb2JhbF9TYWxlcyksIGRlY3JlYXNpbmcgPSBGQUxTRV0NCm9yZGVyZWQkUGxhdGZvcm0gPC0gYXNfZmFjdG9yKG9yZGVyZWQkUGxhdGZvcm0pDQoNCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiUGxhdGZvcm0iDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIkdsb2JhbCBTYWxlcyAoaW4gbWlvKSINCg0KKQ0KDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoUGxhdGZvcm0sR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9IlNhbGVzIEFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBBbW91bnQgYnkgUGxhdGZvcm0iLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCmBgYA0KV2llIHNpY2ggaGVyYXVzc3RlbGx0IGlzdCBkaWVzIGplZG9jaCBuaWNodCBkaWUgUGxhdGZvcm0gd2VsY2hlcyBkaWUgbWVpc3RlbiBHYW1lcmVsZWFzZXMgaGF0Lg0KDQpOdW4gYW5hbHpzaWVyZW4gd2lyIGRpZSB1bnRlcnNjaGllZGUgZGVyIFJlZ2lvbmVuLg0KDQpIaWVyenUgdmVyd2VuZGVuIHdpciBzb3dvaGwgc29ydGVkIGJhciBwbG90cyBzb3dpZSB1bSBlaW5lbiBiZXNzZXJlbiDDnGJlcmJsaWNrIMO8YmVyIGRpZSBQcm96ZW50dWFsdmVydGVpbHVuZyBkZXIgS29uc29sZW4gaW4gZGVuIGVpbnplbG5lbiBSZWdpb25lbiBQaWUgY2hhcnRzLg0KDQpFaW56dXdlbmRlbiBoaWVyYmVpIGlzdCwgZGFzcyBkaWUgUmVnaW9uZW4gbmF0w7xybGljaCB1bnRlcnNjaGllZGxpY2ggdmllbGUgRWlud29obmVyIGhhYmVuLkVpbiB2ZXJnbGVpY2ggZGVyIGFic29sdXRlbiBTYWxlc3dlcnRlIGlzdCBoaWVyYmVpIG5hdMO8cmxpY2ggbnVyIHdlbmlnIGF1c3NjaGxhZ2dlYmVuZCB6ZWlndCBhYmVyIGVpbmVuIGdlbmVyZWxsZW4gYmVsaWVidGhlaXRzdHJlbmQgZGVyIEtvbnNvbGVuIGF1Zi4NCmBgYHtyIHBsb3QoUGxhdGZvcm1SYW5raW5nX0VVKSwgZWNobyA9IFRSVUUsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdtYXJrdXAnLH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQbGF0Zm9ybSkgJT4lIA0KICBzdW1tYXJpemUoc3VtKEVVX1NhbGVzKSkgICU+JQ0KcmVuYW1lKA0KICAgIEdsb2JhbF9TYWxlcyA9ICJzdW0oRVVfU2FsZXMpIg0KICAgICkNCmdyb3VwZWQkR2xvYmFsX1NhbGVzPC1hc192ZWN0b3IoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpDQpvcmRlcmVkIDwtIGdyb3VwZWRbb3JkZXIoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpLCBkZWNyZWFzaW5nID0gRkFMU0VdDQpvcmRlcmVkJFBsYXRmb3JtIDwtIGFzX2ZhY3RvcihvcmRlcmVkJFBsYXRmb3JtKQ0KDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIlBsYXRmb3JtIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJFVSBTYWxlcyAoaW4gbWlvKSINCg0KKQ0KDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoUGxhdGZvcm0sR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9IkVVIFNhbGVzIEFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJFVSBTYWxlcyBBbW91bnQgYnkgUGxhdGZvcm0iLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX3BpZSh2YWx1ZXMgPX5HbG9iYWxfU2FsZXMsbGFiZWxzPX5QbGF0Zm9ybSx0ZXh0aW5mbz0nbGFiZWwrcGVyY2VudCcsDQogICAgICAgICAgIG5hbWU9IkVVIFNhbGVzIEFtb3VudCBieSBQdWJsaXNoZXIiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iRVUgU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyIHBsb3QoUGxhdGZvcm1SYW5raW5nX05BKSwgZWNobyA9IFRSVUUsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdtYXJrdXAnLH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQbGF0Zm9ybSkgJT4lIA0KICBzdW1tYXJpemUoc3VtKE5BX1NhbGVzKSkgICU+JQ0KcmVuYW1lKA0KICAgIEdsb2JhbF9TYWxlcyA9ICJzdW0oTkFfU2FsZXMpIg0KICAgICkNCmdyb3VwZWQkR2xvYmFsX1NhbGVzPC1hc192ZWN0b3IoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpDQpvcmRlcmVkIDwtIGdyb3VwZWRbb3JkZXIoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpLCBkZWNyZWFzaW5nID0gRkFMU0VdDQpvcmRlcmVkJFBsYXRmb3JtIDwtIGFzX2ZhY3RvcihvcmRlcmVkJFBsYXRmb3JtKQ0KDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIlBsYXRmb3JtIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJOQSBTYWxlcyAoaW4gbWlvKSINCg0KKQ0KDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoUGxhdGZvcm0sR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9Ik5BIFNhbGVzIEFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJOQSBTYWxlcyBBbW91bnQgYnkgUGxhdGZvcm0iLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX3BpZSh2YWx1ZXMgPX5HbG9iYWxfU2FsZXMsbGFiZWxzPX5QbGF0Zm9ybSx0ZXh0aW5mbz0nbGFiZWwrcGVyY2VudCcsDQogICAgICAgICAgIG5hbWU9Ik5BIFNhbGVzIEFtb3VudCBieSBQdWJsaXNoZXIiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iTkEgU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyIHBsb3QoUGxhdGZvcm1SYW5raW5nX0pQKSwgZWNobyA9IFRSVUUsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdtYXJrdXAnLH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQbGF0Zm9ybSkgJT4lIA0KICBzdW1tYXJpemUoc3VtKEpQX1NhbGVzKSkgICU+JQ0KcmVuYW1lKA0KICAgIEdsb2JhbF9TYWxlcyA9ICJzdW0oSlBfU2FsZXMpIg0KICAgICkNCmdyb3VwZWQkR2xvYmFsX1NhbGVzPC1hc192ZWN0b3IoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpDQpvcmRlcmVkIDwtIGdyb3VwZWRbb3JkZXIoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpLCBkZWNyZWFzaW5nID0gRkFMU0VdDQpvcmRlcmVkJFBsYXRmb3JtIDwtIGFzX2ZhY3RvcihvcmRlcmVkJFBsYXRmb3JtKQ0KDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIlBsYXRmb3JtIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJKUCBTYWxlcyAoaW4gbWlvKSINCg0KKQ0KDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoUGxhdGZvcm0sR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9IkpQIFNhbGVzIEFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJKUCBTYWxlcyBBbW91bnQgYnkgUGxhdGZvcm0iLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX3BpZSh2YWx1ZXMgPX5HbG9iYWxfU2FsZXMsbGFiZWxzPX5QbGF0Zm9ybSx0ZXh0aW5mbz0nbGFiZWwrcGVyY2VudCcsDQogICAgICAgICAgIG5hbWU9IkpQIFNhbGVzIEFtb3VudCBieSBQbGF0Zm9ybSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJKUCBTYWxlcyBBbW91bnQgYnkgUGxhdGZvcm0iLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCmBgYA0KSW0gZ2VuZW5zYXR6IHp1ciBFVSwgaW4gZGVyIGRhcyBqYXBhbmlzY2hlIHVudGVybmVobWVuIFNvbnkgbWl0IGRlciBQUzIgdW5kIFBTMyBkaWUgbGlzdGUgYW5mw7xocnQsIGhhdCBpbiBkZW4gVVNBIGRhcyBMYW5kZXNlaWdlbmUgc29mdHdhcmV1bnRlcm5laG1lbiBNaWNyb3NvZnQgbWl0IGRlciBYYm94MzYwIGRpZSBOYXNlIHZvcm4uIEluIEphcGFuIGhpbmdlZ2VuIGlzdCB3aWUgenUgZXJ3YXJ0ZW4gZGVyIGphcGFuaXNjaGUgaGVyc3RlbGxlciBOaW50ZW5kbyBtaXQgZGVtIERTIGRlciBNYXJrZsO8aHJlci4NCg0KVW0gc2ljaCBkYXMgR2FuemUgZXR3YXMgZ2VuYXVlciBhbnp1c2NoYXVlbiBiZXRyYWNodGVuIHdpciBkaWUgQW56YWhsIGRlciBTYWxlcyBwZXIgUGxhdGZvcm0gaW0gVmVybGF1ZiBkZXIgSmFocmUuDQoNClVtIGVpbmUgw7xiZXJsYWR1bmcgZGVzIERpYWdyYW1tcyB6dSB2ZXJoaW5kZXJuIHdlcmRlbiBoaWVyIGFsbGVyZGluZ3MgbnVyIFBsYXR0Zm9ybWVuIG1pdCBtaW5kZXN0ZW5zIDYwIG1pbyBpbiBTYWxlcyBpbSBlbnRzcHJlY2hlbmRlbiBKYWhyIGJlcsO8Y2tzaWNodGlndC4gRGllcyBoYXQgZGVuIE5hY2h0ZWlsIGRhcyBlaW5pZ2Ugei5UIHdpY2h0aWdlIERhdGVuIEZlaGxlbiwgZWluIFdlZ2xhc3NlbiBlYmVuamVuZXMgRmlsdGVycyBmw7xydCBhYmVyIHp1IGtvbXBsZXR0ZXIgVW7DvGJlcnNpY2h0bGljaGtlaXQuDQpgYGB7ciBwbG90KFNhbGVzUGVyUGxhdGZvcm1ieVllYXIpLCBpbmNsdWRlPVRSVUUsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0nbWFya3VwJywgfQ0KDQpncm91cGVkIDwtIHZnc2FsZXMgICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBncm91cF9ieShZZWFyLCBQbGF0Zm9ybSkgJT4lDQogIGRwbHlyOjpzdW1tYXJpemUoZ3Jfc3VtID0gc3VtKEdsb2JhbF9TYWxlcykpICU+JSBmaWx0ZXIoWWVhciE9J04vQScpJT4lZmlsdGVyKFllYXIhPTIwMjApICU+JSBmaWx0ZXIoWWVhciE9JzIwMTcnKSAgJT4lIGZpbHRlcihncl9zdW0+NjApJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KZ3JvdXBlZCA8LSBncm91cGVkICU+JWFycmFuZ2UoZGVzYyhncl9zdW0pKSAlPiUgDQogIGdyb3VwX2J5KFllYXIsIFBsYXRmb3JtKSAlPiUNCiAgc2xpY2UoMTozKQ0KDQpmaWx0ZXJlZCA8LSBncm91cGVkICU+JSBzZWxlY3QoWWVhcixQbGF0Zm9ybSxncl9zdW0pDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJZZWFyIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJTYWxlcyBwZXIgUGxhdGZvcm0gKGluIG1pbykiDQoNCikNCg0KDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gfmdyX3N1bSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdub25lJywgc3RhY2tncm91cCA9ICdvbmUnLGNvbG9yID0gflBsYXRmb3JtKSU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBwZXIgUGxhdGZvcm0gZnJvbSAxOTgwLTIwMTYiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCg0KYGBgDQpIaWVyIGVya2VubmVuIHdpciBkYXMgUGxhdGZvcm0sIHdpZSB6dSBlcndhcnRlbiwgbWVpc3Qga3VyeiBuYWNoIFJlbGVhc2UgZGllIGdyw7bDn3RlbiBWZXJrYXVmc3phaGxlbiB2ZXJ6ZWljaG5lbi4NCg0KDQoNCg0KTnVuIHN0ZWxsdCBzaWNoIGRpZSBGcmFnZSBvYiBzaWNoIG5lYmVuIGJlc3RpbW10ZW4gUGxhdGZvcm1lbiBhdWNoIGJlc3RpbW10ZSBFbnR3aWNrbGVyL1B1Ymxpc2hlciBow6R1ZmVuLiBIaWVyYmVpIGdlaGVuIHdpciBkYXZvbiBhdXMgZGFzIHZlcm11dGxpY2ggTmludGVuZG8gdW5kIEVBIGRpZSBMaXN0ZSBhbmbDvGhyZW4uDQpIaWVyenUgdmVyd2VuZGVuIHdpciB3aWVkZXJ1bSBzb3J0ZWQgQmFyLUNoYXJ0cyB1bmQga8O8cnplbiBkaWUgTmFtZW4gdW0gZGllIEJlZ3JpZmZlICJFbnRlcnRhaW5tZW50IiwgIkludGVyYWN0aXZlIiwgIkdhbWUiLCAiR2FtZXMiIHVuZCAiU3R1ZGlvcyIgZGEgZGllcyBkaWUgTmFtZW4gbnVyIHVubsO2dGlnIHZlcmzDpG5nZXJ0IHVuZCBGaWx0ZXJuIFB1Ymxpc2hlciBtaXQgR2VyaW5nZW4gQW56YWhsIGFuIEdhbWUgUmVsZWFzZXMuDQoNCmBgYHtyIHBsb3QyLCBlY2hvID0gVFJVRSwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0nbWFya3VwJywgfQ0KZ3JvdXBlZCA8LSB2Z3NhbGVzICAlPiUgDQogIGdyb3VwX2J5KFB1Ymxpc2hlcikgJT4lIA0KICBzdW1tYXJpemUoQW56YWhsID1uKCkpICU+JSAgDQogIGZpbHRlcihBbnphaGw+MTAwKSAlPiUgZmlsdGVyKFB1Ymxpc2hlciE9IlVua25vd24iKQ0KDQpvcmRlcmVkIDwtIGdyb3VwZWRbb3JkZXIoZ3JvdXBlZCRBbnphaGwpLCBkZWNyZWFzaW5nID0gRkFMU0VdDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiRW50ZXJ0YWlubWVudCIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiSW50ZXJhY3RpdmUiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIlN0dWRpb3MiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIkdhbWVzIikNCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJHYW1lIikNCm9yZGVyZWQkUHVibGlzaGVyIDwtIGFzX2ZhY3RvcihvcmRlcmVkJFB1Ymxpc2hlcikNCg0KDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJQdWJsaXNoZXIiDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIkFuemFobCINCikNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoUHVibGlzaGVyLEFuemFobCwgLmRlc2M9InRydWUiKSwNCiAgICAgICAgICAgeT1+QW56YWhsLA0KICAgICAgICAgICBuYW1lPSJHYW1lIEFtb3VudCBieSBQdWJsaXNoZXIiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iR2FtZSBBbW91bnQgYnkgUHVibGlzaGVyIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICANCiAgICAgICAgICkNCmBgYA0KDQpgYGB7ciBwbG90KFB1Ymxpc2hlclJhbmtpbmdfR2xvYmFsKSwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQdWJsaXNoZXIpICU+JSANCiAgc3VtbWFyaXplKEFuemFobCA9bigpLHN1bShHbG9iYWxfU2FsZXMpKSAlPiUNCiAgZmlsdGVyKEFuemFobD4xMDApICU+JQ0KcmVuYW1lKA0KICAgIEdsb2JhbF9TYWxlcyA9ICJzdW0oR2xvYmFsX1NhbGVzKSINCiAgICApDQpncm91cGVkJEdsb2JhbF9TYWxlczwtYXNfdmVjdG9yKGdyb3VwZWQkR2xvYmFsX1NhbGVzKQ0Kb3JkZXJlZCA8LSBncm91cGVkW29yZGVyKGdyb3VwZWQkR2xvYmFsX1NhbGVzKSwgZGVjcmVhc2luZyA9IEZBTFNFXQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIkVudGVydGFpbm1lbnQiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIkludGVyYWN0aXZlIikNCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJTdHVkaW9zIikNCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJHYW1lcyIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiR2FtZSIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LSBhc19mYWN0b3Iob3JkZXJlZCRQdWJsaXNoZXIpDQoNCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiUHVibGlzaGVyIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJHbG9iYWwgU2FsZXMgKGluIG1pbykiDQoNCikNCg0KDQpvcmRlcmVkJT4lDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF9iYXJzKHg9fmZjdF9yZW9yZGVyKFB1Ymxpc2hlcixHbG9iYWxfU2FsZXMsIC5kZXNjPSJ0cnVlIiksDQogICAgICAgICAgIHk9fkdsb2JhbF9TYWxlcywNCiAgICAgICAgICAgbmFtZT0iU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBBbW91bnQgYnkgUHVibGlzaGVyIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQpgYGANCg0KQXVmZsOkbGxpZyBpc3QgaGllciBkaWUgZGlza3JlcGFueiB6d2lzY2hlbiBBbnphaGwgZGVyIFNwaWVsZXJlbGVhc2VzIHVuZCBBbnphaGwgZGVyIFNwaWVsZXZlcmvDpHVmZS4gSW0gZ2VnZW5zYXR6IHp1IGRlciBBbnphaGwgZGVyIFNwaWVsZSAoYmVpIGRlbSBOaW50ZW5kbyBudXIgYXVmIHBsYXR6IDYgU2l0eikgZG9taW5pZXJ0IE5pbnRlbmRvIGltIGFuemFobCBkZXIgU2FsZXMuDQoNCg0KTnVuIHN0ZWxsdCBzaWNoIHdpZWRlciBlaW5tYWwgZGllIEZyYWdlIG9iIHNpY2ggZGllcyBpbiBCZXN0aW1tdGVuIHRlaWxlbiBkZXIgV2VsdCB1bnRlcnNjaGVpZGV0IHVuZCBoaWVyenUgdmVyd2VuZGVuIHdpciB3aWVkZXJ1bSBkaWUgU29ydGVkQmFyL1BpZWNoYXJ0IGtvbWJvIHVuZCBkaWUgYmVyZWl0cyBnZW5hbm50ZW4gRmlsdGVyDQoNCmBgYHtyIHBsb3QoUHVibGlzaGVyUmFua2luZ19FVSksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQpncm91cGVkIDwtIHZnc2FsZXMgICU+JSANCiAgZ3JvdXBfYnkoUHVibGlzaGVyKSAlPiUgDQogIHN1bW1hcml6ZShBbnphaGwgPW4oKSxzdW0oRVVfU2FsZXMpKSAlPiUNCiAgZmlsdGVyKEFuemFobD4xMDApICU+JQ0KcmVuYW1lKA0KICAgIEdsb2JhbF9TYWxlcyA9ICJzdW0oRVVfU2FsZXMpIg0KICAgICkNCmdyb3VwZWQkR2xvYmFsX1NhbGVzPC1hc192ZWN0b3IoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpDQpvcmRlcmVkIDwtIGdyb3VwZWRbb3JkZXIoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpLCBkZWNyZWFzaW5nID0gRkFMU0VdDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiRW50ZXJ0YWlubWVudCIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiSW50ZXJhY3RpdmUiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIlN0dWRpb3MiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIkdhbWVzIikNCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJHYW1lIikNCm9yZGVyZWQkUHVibGlzaGVyIDwtIGFzX2ZhY3RvcihvcmRlcmVkJFB1Ymxpc2hlcikNCg0KDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJQdWJsaXNoZXIiDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIkVVIFNhbGVzIChpbiBtaW8pIg0KDQopDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoUHVibGlzaGVyLEdsb2JhbF9TYWxlcywgLmRlc2M9InRydWUiKSwNCiAgICAgICAgICAgeT1+R2xvYmFsX1NhbGVzLA0KICAgICAgICAgICBuYW1lPSJFVSBTYWxlcyBBbW91bnQgYnkgUHVibGlzaGVyIikgJT4lIA0KICBsYXlvdXQodGl0bGU9IkVVIFNhbGVzIEFtb3VudCBieSBQdWJsaXNoZXIiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCg0Kb3JkZXJlZCU+JQ0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfcGllKHZhbHVlcyA9fkdsb2JhbF9TYWxlcyxsYWJlbHM9flB1Ymxpc2hlciwNCiAgICAgICAgICAgbmFtZT0iRVUgU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJFVSBTYWxlcyBBbW91bnQgYnkgUHVibGlzaGVyIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQpgYGANCg0KYGBge3IgcGxvdChQdWJsaXNoZXJSYW5raW5nX05BKSwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQdWJsaXNoZXIpICU+JSANCiAgc3VtbWFyaXplKEFuemFobCA9bigpLHN1bShOQV9TYWxlcykpICU+JQ0KICBmaWx0ZXIoQW56YWhsPjEwMCkgJT4lDQpyZW5hbWUoDQogICAgR2xvYmFsX1NhbGVzID0gInN1bShOQV9TYWxlcykiDQogICAgKQ0KZ3JvdXBlZCRHbG9iYWxfU2FsZXM8LWFzX3ZlY3Rvcihncm91cGVkJEdsb2JhbF9TYWxlcykNCm9yZGVyZWQgPC0gZ3JvdXBlZFtvcmRlcihncm91cGVkJEdsb2JhbF9TYWxlcyksIGRlY3JlYXNpbmcgPSBGQUxTRV0NCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJFbnRlcnRhaW5tZW50IikNCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJJbnRlcmFjdGl2ZSIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiU3R1ZGlvcyIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiR2FtZXMiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIkdhbWUiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC0gYXNfZmFjdG9yKG9yZGVyZWQkUHVibGlzaGVyKQ0KDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIlB1Ymxpc2hlciINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiTkEgU2FsZXMgKGluIG1pbykiDQoNCikNCg0Kb3JkZXJlZCU+JQ0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfYmFycyh4PX5mY3RfcmVvcmRlcihQdWJsaXNoZXIsR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9Ik5BIFNhbGVzIEFtb3VudCBieSBQdWJsaXNoZXIiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iTkEgU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KDQpvcmRlcmVkJT4lDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF9waWUodmFsdWVzID1+R2xvYmFsX1NhbGVzLGxhYmVscz1+UHVibGlzaGVyLHRleHRpbmZvPSdsYWJlbCtwZXJjZW50JywNCiAgICAgICAgICAgbmFtZT0iTkEgU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJOQSBTYWxlcyBBbW91bnQgYnkgUHVibGlzaGVyIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQpgYGANCg0KYGBge3IgcGxvdChQdWJsaXNoZXJSYW5raW5nX0pQKSwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQdWJsaXNoZXIpICU+JSANCiAgc3VtbWFyaXplKEFuemFobCA9bigpLHN1bShKUF9TYWxlcykpICU+JQ0KICBmaWx0ZXIoQW56YWhsPjEwMCkgJT4lDQpyZW5hbWUoDQogICAgR2xvYmFsX1NhbGVzID0gInN1bShKUF9TYWxlcykiDQogICAgKQ0KZ3JvdXBlZCRHbG9iYWxfU2FsZXM8LWFzX3ZlY3Rvcihncm91cGVkJEdsb2JhbF9TYWxlcykNCm9yZGVyZWQgPC0gZ3JvdXBlZFtvcmRlcihncm91cGVkJEdsb2JhbF9TYWxlcyksIGRlY3JlYXNpbmcgPSBGQUxTRV0NCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJFbnRlcnRhaW5tZW50IikNCm9yZGVyZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwob3JkZXJlZCRQdWJsaXNoZXIsICJJbnRlcmFjdGl2ZSIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiU3R1ZGlvcyIpDQpvcmRlcmVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKG9yZGVyZWQkUHVibGlzaGVyLCAiR2FtZXMiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChvcmRlcmVkJFB1Ymxpc2hlciwgIkdhbWUiKQ0Kb3JkZXJlZCRQdWJsaXNoZXIgPC0gYXNfZmFjdG9yKG9yZGVyZWQkUHVibGlzaGVyKQ0KDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIlB1Ymxpc2hlciINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiSlAgU2FsZXMgKGluIG1pbykiDQoNCikNCg0Kb3JkZXJlZCU+JQ0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfYmFycyh4PX5mY3RfcmVvcmRlcihQdWJsaXNoZXIsR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9IkpQIFNhbGVzIEFtb3VudCBieSBQdWJsaXNoZXIiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iSlAgU2FsZXMgQW1vdW50IGJ5IFB1Ymxpc2hlciIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KDQpvcmRlcmVkJT4lDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF9waWUodmFsdWVzID1+R2xvYmFsX1NhbGVzLGxhYmVscz1+UHVibGlzaGVyLA0KICAgICAgICAgICBuYW1lPSJKUCBTYWxlcyBBbW91bnQgYnkgUHVibGlzaGVyIikgJT4lIA0KICBsYXlvdXQodGl0bGU9IkpQIFNhbGVzIEFtb3VudCBieSBQdWJsaXNoZXIiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCmBgYA0KWndpc2NoZW4gRVUgdW5kIFVTIGxhc3NlbiBzaWNoIGhpZXIga2F1bSBVbnRlcnNjaGllZGUgZmVzdHN0ZWxsZW4gaW4gSmFwYW4gaGluZ2VnZW4gaXN0IGVpbmUgdmVyc2NoaWVidW5nIHp1IGVya2VubmVuLiBKYXBhbmlzY2hlIFB1Ymxpc2hlciBmw7xocmVuIGhpZXJiZWkgZGllIExpc3RlIGFuIHVuZCBkcsOkbmdlbiBhbmRlcmUgZ3Jvw59lIHVudGVybmVobWVuIHZvbiBkZW4gVG9wIHNwb3RzLg0KDQpOdW4gc2NoYXVlbiB3aXIgdW5zIGRpZSBHZW5yZXZlcnRlaWx1bmcgdm9uIFZpZGVvc3BpZWxlbiBhbi4gSGllcnp1IHZlcndlbmRlbiB3aXIgd2llZGVydW0gZGllIEFsdGJla2FubnRlIHNvcnRlZCBCYXIvUGllLUNoYXJ0IGtvbWJvLg0KDQpgYGB7ciBwbG90KEdlbnJlQW1vdW50X0dMb2JhbCksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQpncm91cGVkIDwtIHZnc2FsZXMgICU+JSANCiAgZ3JvdXBfYnkoR2VucmUpICU+JSANCiAgc3VtbWFyaXplKEFuemFobCA9bigpKQ0KDQpncm91cGVkJEFuemFobDwtYXNfdmVjdG9yKGdyb3VwZWQkQW56YWhsKQ0Kb3JkZXJlZCA8LSBncm91cGVkW29yZGVyKGdyb3VwZWQkQW56YWhsKSwgZGVjcmVhc2luZyA9IEZBTFNFXQ0Kb3JkZXJlZCRHZW5yZSA8LSBhc19mYWN0b3Iob3JkZXJlZCRHZW5yZSkNCg0KDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJHZW5yZSINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiQW56YWhsIg0KDQopDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoR2VucmUsQW56YWhsLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5BbnphaGwsDQogICAgICAgICAgIG5hbWU9IkFtb3VudCBieSBHZW5yZSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJBbW91bnQgYnkgR2VucmUiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCg0Kb3JkZXJlZCU+JQ0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfcGllKHZhbHVlcyA9fkFuemFobCxsYWJlbHM9fkdlbnJlLA0KICAgICAgICAgICBuYW1lPSJBbW91bnQgYnkgR2VucmUiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iQW1vdW50IGJ5IEdlbnJlIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQpgYGANCkhpZXJiZWkgaXN0IHp1IGVya2VubmVuIGRhcyBBY3Rpb24gdW5kIFNwb3J0cyBlaW4gR3Jvw590ZWlsICgzNCUpIGRlciBHZW5yZXMgYXVzbWFjaGVuLiBEaWUgRnJhZ2UgaXN0IGplZG9jaCB3aWUgc2luZCBkaWUgVmVya8OkdWZlIHZlcnRlaWx0IHVuZCBiZWVpbmZsdXNzdCBkaWUgYW56YWhsIGRlciBHYW1lcyBwcm8gR2VucmUgaXJnZW5kd2llIGRpZSBWZXJrYXVmc3phaGxlbj8NCmBgYHtyIHBsb3QoU2FsZXNCeUdlbnJlX0dsb2JhbCksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQoNCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShHZW5yZSkgJT4lIA0KICBzdW1tYXJpemUoc3VtKEdsb2JhbF9TYWxlcykpICAlPiUNCnJlbmFtZSgNCiAgICBHbG9iYWxfU2FsZXMgPSAic3VtKEdsb2JhbF9TYWxlcykiDQogICAgKQ0KZ3JvdXBlZCRHbG9iYWxfU2FsZXM8LWFzX3ZlY3Rvcihncm91cGVkJEdsb2JhbF9TYWxlcykNCm9yZGVyZWQgPC0gZ3JvdXBlZFtvcmRlcihncm91cGVkJEdsb2JhbF9TYWxlcyksIGRlY3JlYXNpbmcgPSBGQUxTRV0NCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiR2VucmUiDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIlNhbGVzIChpbiBtaW8pIg0KDQopDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoR2VucmUsR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9IlNhbGVzIGJ5IEdlbnJlIikgJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX3BpZSh2YWx1ZXMgPX5HbG9iYWxfU2FsZXMsbGFiZWxzPX5HZW5yZSwNCiAgICAgICAgICAgbmFtZT0iU2FsZXMgYnkgR2VucmUiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iU2FsZXMgYnkgR2VucmUiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgKQ0KYGBgDQpIaWVyYmVpIGVya2VubmVuIHdpciBkYXMgZXMgZWluaWdlIFVudGVyc2NoaWVkZSBnaWJ0IEFjdGlvbiB1bmQgc3BvcnRzIG1hY2hlbiBqZWRvY2ggd2VpdGVyaGluIGVpbmVuIEdyb3N0ZWlsIGRlcyBNYXJrdHMgYXVzLg0KDQpOdW4gc2NoYXVlbiB3aXIgdW5zIGRpZSBVbnRlcnNjaGVpZGUgaW4gZGVuIFJlZ2lvbmVuIGFuLg0KYGBge3IgcGxvdChTYWxlc0J5R2VucmVfRVUpLCBlY2hvID0gVFJVRSwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0nbWFya3VwJywgfQ0KDQpncm91cGVkIDwtIHZnc2FsZXMgICU+JSANCiAgZ3JvdXBfYnkoR2VucmUpICU+JSANCiAgc3VtbWFyaXplKHN1bShFVV9TYWxlcykpICAlPiUNCnJlbmFtZSgNCiAgICBHbG9iYWxfU2FsZXMgPSAic3VtKEVVX1NhbGVzKSINCiAgICApDQpncm91cGVkJEdsb2JhbF9TYWxlczwtYXNfdmVjdG9yKGdyb3VwZWQkR2xvYmFsX1NhbGVzKQ0Kb3JkZXJlZCA8LSBncm91cGVkW29yZGVyKGdyb3VwZWQkR2xvYmFsX1NhbGVzKSwgZGVjcmVhc2luZyA9IEZBTFNFXQ0KDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJHZW5yZSINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiU2FsZXMgKGluIG1pbykiDQoNCikNCg0Kb3JkZXJlZCU+JQ0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfYmFycyh4PX5mY3RfcmVvcmRlcihHZW5yZSxHbG9iYWxfU2FsZXMsIC5kZXNjPSJ0cnVlIiksDQogICAgICAgICAgIHk9fkdsb2JhbF9TYWxlcywNCiAgICAgICAgICAgbmFtZT0iU2FsZXMgYnkgR2VucmUgKEVVKSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBieSBHZW5yZSAoRVUpIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX3BpZSh2YWx1ZXMgPX5HbG9iYWxfU2FsZXMsbGFiZWxzPX5HZW5yZSwNCiAgICAgICAgICAgbmFtZT0iU2FsZXMgYnkgR2VucmUgKEVVKSIpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBieSBHZW5yZSAoRVUpIiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICkNCmBgYA0KDQpgYGB7ciBwbG90KFNhbGVzQnlHZW5yZV9OQSksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQoNCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShHZW5yZSkgJT4lIA0KICBzdW1tYXJpemUoc3VtKE5BX1NhbGVzKSkgICU+JQ0KcmVuYW1lKA0KICAgIEdsb2JhbF9TYWxlcyA9ICJzdW0oTkFfU2FsZXMpIg0KICAgICkNCmdyb3VwZWQkR2xvYmFsX1NhbGVzPC1hc192ZWN0b3IoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpDQpvcmRlcmVkIDwtIGdyb3VwZWRbb3JkZXIoZ3JvdXBlZCRHbG9iYWxfU2FsZXMpLCBkZWNyZWFzaW5nID0gRkFMU0VdDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIkdlbnJlIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJTYWxlcyAoaW4gbWlvKSINCg0KKQ0KDQpvcmRlcmVkJT4lDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF9iYXJzKHg9fmZjdF9yZW9yZGVyKEdlbnJlLEdsb2JhbF9TYWxlcywgLmRlc2M9InRydWUiKSwNCiAgICAgICAgICAgeT1+R2xvYmFsX1NhbGVzLA0KICAgICAgICAgICBuYW1lPSJTYWxlcyBieSBHZW5yZSAoTkEpIikgJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIChOQSkiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCg0Kb3JkZXJlZCU+JQ0KICBwbG90X2x5KCkgJT4lIA0KICBhZGRfcGllKHZhbHVlcyA9fkdsb2JhbF9TYWxlcyxsYWJlbHM9fkdlbnJlLA0KICAgICAgICAgICBuYW1lPSJTYWxlcyBieSBHZW5yZSAoTkEpIikgJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIChOQSkiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgKQ0KYGBgDQoNCmBgYHtyIHBsb3QoU2FsZXNCeUdlbnJlX0pQKSwgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCg0KZ3JvdXBlZCA8LSB2Z3NhbGVzICAlPiUgDQogIGdyb3VwX2J5KEdlbnJlKSAlPiUgDQogIHN1bW1hcml6ZShzdW0oSlBfU2FsZXMpKSAgJT4lDQpyZW5hbWUoDQogICAgR2xvYmFsX1NhbGVzID0gInN1bShKUF9TYWxlcykiDQogICAgKQ0KZ3JvdXBlZCRHbG9iYWxfU2FsZXM8LWFzX3ZlY3Rvcihncm91cGVkJEdsb2JhbF9TYWxlcykNCm9yZGVyZWQgPC0gZ3JvdXBlZFtvcmRlcihncm91cGVkJEdsb2JhbF9TYWxlcyksIGRlY3JlYXNpbmcgPSBGQUxTRV0NCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiR2VucmUiDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIlNhbGVzIg0KDQopDQoNCm9yZGVyZWQlPiUNCiAgcGxvdF9seSgpICU+JSANCiAgYWRkX2JhcnMoeD1+ZmN0X3Jlb3JkZXIoR2VucmUsR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgIG5hbWU9IlNhbGVzIGJ5IEdlbnJlIChKUCkiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iU2FsZXMgYnkgR2VucmUgKEpQKSIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KDQpvcmRlcmVkJT4lDQogIHBsb3RfbHkoKSAlPiUgDQogIGFkZF9waWUodmFsdWVzID1+R2xvYmFsX1NhbGVzLGxhYmVscz1+R2VucmUsDQogICAgICAgICAgIG5hbWU9IlNhbGVzIGJ5IEdlbnJlIChKUCkiKSAlPiUgDQogIGxheW91dCh0aXRsZT0iU2FsZXMgYnkgR2VucmUgKEpQKSIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICApDQpgYGANCkhpZXJiZWkgZXJrZW5uZW4gd2lyIHdpZWRlciBlaW5tYWwgZGFzIFVTIHVuZCBFVSByZWNodCDDpGhubGljaCBzaW5kIHdvaGluZ2VnZW4gSmFwYW4gZWluIGfDpG56bGljaCBhbmRlcmVzIEdlbnJlc2hlbWEgZXJrZW5uZW4gbMOkc3N0LiBJbiBKYXBhbiBkb21pbmllcnQgUm9sZS1QbGF5aW5nIHdlbGNoZXMgc2ljaCBpbiBFVSB1bmQgVVMgbnVyIGF1ZiBwbGF0eiA3IGJlZmluZGV0Lg0KDQpOdW4gc2NoYXVlbiB3aXIgdW5zIGRpZSBHZW5yZWVudHdpY2tsdW5nIMO8YmVyIGRpZSBKYWhyZSBhbi4gSGllcnp1IHZlcndlbmRlbiB3aXIgTGluZVBsb3RzLg0KYGBge3IgcGxvdChBbW91bnRPZkdhbWVzQnlHZW5yZWJ5WWVhciksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQoNCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGdyb3VwX2J5KFllYXIsIEdlbnJlKSAlPiUNCiAgZHBseXI6OnN1bW1hcml6ZShBbnphaGwgPW4oKSkgJT4lIGZpbHRlcihZZWFyIT0nTi9BJyklPiVmaWx0ZXIoWWVhciE9MjAyMCkgJT4lIGZpbHRlcihZZWFyIT0nMjAxNycpICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkNCg0KDQpmaWx0ZXJlZCA8LSBncm91cGVkICU+JSBzZWxlY3QoWWVhcixHZW5yZSxBbnphaGwpDQpheCA8LSBsaXN0KA0KICB0aXRsZSA9ICJZZWFyIg0KKQ0KDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJBbnphaGwiDQoNCikNCg0KZmlsdGVyZWQgJT4lDQpwbG90X2x5KCkgJT4lIA0KICBhZGRfbGluZXMoeD1+WWVhciwNCiAgICAgICAgICAgeT1+QW56YWhsLCBjb2xvcj1+R2VucmUpDQoNCg0KDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gfkFuemFobCwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdub25lJywgZmlsbCA9ICd0b3plcm95Jyxjb2xvciA9IH5HZW5yZSklPiUgDQogIGxheW91dCh0aXRsZT0iQW1vdW50IGJ5IEdlbnJlIGZyb20gMTk4MC0yMDE2IiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQoNCmZpbHRlcmVkICU+JQ0KcGxvdF9seSh4ID0gflllYXIsIHkgPSB+QW56YWhsLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ25vbmUnLCBzdGFja2dyb3VwID0gJ29uZScsY29sb3IgPSB+R2VucmUpJT4lIA0KICBsYXlvdXQodGl0bGU9IkFtb3VudCBieSBHZW5yZSBmcm9tIDE5ODAtMjAxNiIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiUGVyY2VudCAlIg0KDQopDQoNCmZpbHRlcmVkICU+JQ0KcGxvdF9seSh4ID0gflllYXIsIHkgPSB+QW56YWhsLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ25vbmUnLCBzdGFja2dyb3VwID0gJ29uZScsZ3JvdXBub3JtID0gJ3BlcmNlbnQnLGNvbG9yID0gfkdlbnJlKSU+JSANCiAgbGF5b3V0KHRpdGxlPSJNYXJrZXRhbW91bnQgZ2VucmVzaGlmdCBpbiAlIGZyb20gMTk4MC0yMDE2IiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQpgYGANClNjaGF1ZW4gd2lyIHVucyBhbiB3aWUgc2ljaCBkaWUgdmVya8OkdWZlIGVudHdpY2tlbHQgaGFiZW4uDQpgYGB7ciBwbG90KFNhbGVzQnlHZW5yZWJ5WWVhciksIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQoNCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGdyb3VwX2J5KFllYXIsIEdlbnJlKSAlPiUNCiAgZHBseXI6OnN1bW1hcml6ZShncl9zdW0gPSBzdW0oR2xvYmFsX1NhbGVzKSkgJT4lIGZpbHRlcihZZWFyIT0nTi9BJyklPiVmaWx0ZXIoWWVhciE9MjAyMCkgJT4lIGZpbHRlcihZZWFyIT0nMjAxNycpICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkNCg0KDQpmaWx0ZXJlZCA8LSBncm91cGVkICU+JSBzZWxlY3QoWWVhcixHZW5yZSxncl9zdW0pDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIlllYXIiDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIkdsb2JhbF9TYWxlcyINCg0KKQ0KDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoKSAlPiUgDQogIGFkZF9saW5lcyh4PX5ZZWFyLA0KICAgICAgICAgICB5PX5ncl9zdW0sIGNvbG9yPX5HZW5yZSkgJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIGZyb20gMTk4MC0yMDE2IiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQoNCg0KDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gfmdyX3N1bSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdub25lJywgZmlsbCA9ICd0b3plcm95Jyxjb2xvciA9IH5HZW5yZSkgJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIGZyb20gMTk4MC0yMDE2IiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQoNCmZpbHRlcmVkICU+JQ0KcGxvdF9seSh4ID0gflllYXIsIHkgPSB+Z3Jfc3VtLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ25vbmUnLCBzdGFja2dyb3VwID0gJ29uZScsY29sb3IgPSB+R2VucmUpJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIGZyb20gMTk4MC0yMDE2IiwNCiAgICAgICAgIHhheGlzID0gYXgsDQogICAgICAgICB5YXhpcyA9IGF5DQogICAgICAgICApDQpheSA8LSBsaXN0KA0KICB0aXRsZSA9ICJQZXJjZW50ICUiDQoNCikNCmZpbHRlcmVkICU+JQ0KcGxvdF9seSh4ID0gflllYXIsIHkgPSB+Z3Jfc3VtLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ25vbmUnLCBzdGFja2dyb3VwID0gJ29uZScsZ3JvdXBub3JtID0gJ3BlcmNlbnQnLGNvbG9yID0gfkdlbnJlKSU+JSANCiAgbGF5b3V0KHRpdGxlPSJNYXJrZXRzaGFyZSBnZW5yZXNoaWZ0IGluICUgZnJvbSAxOTgwLTIwMTYiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCmBgYA0KTnVuIHN0ZWxsdCBzaWNoIGRpZSBGcmFnZSBoYWIgc2ljaCBkaWUgVmVya8OkdWZlIMOkaG5saWNoIGRlciBhbnphaGwgZGVyIEdhbWVSZWxlYXNlcyBlbnR3aWNrZWx0Pw0KYGBge3IgcGxvdChTYWxlc1BlckdhbWVQZXJHZW5yZWJ5WWVhciksIGluY2x1ZGU9VFJVRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdtYXJrdXAnLCB9DQoNCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGdyb3VwX2J5KFllYXIsIEdlbnJlKSAlPiUNCiAgZHBseXI6OnN1bW1hcml6ZShncl9zdW0gPSBzdW0oR2xvYmFsX1NhbGVzKS9uKCkpICU+JSBmaWx0ZXIoWWVhciE9J04vQScpJT4lZmlsdGVyKFllYXIhPTIwMjApICU+JSBmaWx0ZXIoWWVhciE9JzIwMTcnKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQoNCg0KZmlsdGVyZWQgPC0gZ3JvdXBlZCAlPiUgc2VsZWN0KFllYXIsR2VucmUsZ3Jfc3VtKQ0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiWWVhciINCikNCg0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiU2FsZXMgcGVyIEdhbWUiDQoNCikNCg0KZmlsdGVyZWQgJT4lDQpwbG90X2x5KCkgJT4lIA0KICBhZGRfbGluZXMoeD1+WWVhciwNCiAgICAgICAgICAgeT1+Z3Jfc3VtLCBjb2xvcj1+R2VucmUpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBwZXIgR2FtZSBieSBHZW5yZSBmcm9tIDE5ODAtMjAxNiIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KDQoNCg0KZmlsdGVyZWQgJT4lDQpwbG90X2x5KHggPSB+WWVhciwgeSA9IH5ncl9zdW0sIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbm9uZScsIGZpbGwgPSAndG96ZXJveScsY29sb3IgPSB+R2VucmUpICU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBwZXIgR2FtZSBieSBHZW5yZSBmcm9tIDE5ODAtMjAxNiIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gfmdyX3N1bSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdub25lJywgc3RhY2tncm91cCA9ICdvbmUnLGNvbG9yID0gfkdlbnJlKSU+JSANCiAgbGF5b3V0KHRpdGxlPSJTYWxlcyBwZXIgR2FtZSBieSBHZW5yZSBmcm9tIDE5ODAtMjAxNiIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheQ0KICAgICAgICAgKQ0KYXkgPC0gbGlzdCgNCiAgdGl0bGUgPSAiUGVyY2VudCAlIg0KDQopDQpmaWx0ZXJlZCAlPiUNCnBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gfmdyX3N1bSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdub25lJywgc3RhY2tncm91cCA9ICdvbmUnLGdyb3Vwbm9ybSA9ICdwZXJjZW50Jyxjb2xvciA9IH5HZW5yZSklPiUgDQogIGxheW91dCh0aXRsZT0iTWFya2V0c2hhcmUgaW4gU2FsZXMgcGVyIEdhbWUgYnkgR2VucmUgZnJvbSAxOTgwLTIwMTYiLA0KICAgICAgICAgeGF4aXMgPSBheCwNCiAgICAgICAgIHlheGlzID0gYXkNCiAgICAgICAgICkNCmBgYA0KDQpXaWUgc2llaHQgZXMgbWl0IEdlbnJlcyBwcm8gcHVibGlzaGVyIGF1cz8NCg0KSGllcnp1IHZlcndlbmRlbiB3aXIgZWluIHN0YWNrZWQgQmFyLVBsb3QuIERhenUgZmlsdGVybiB3aXIgR2VucmVzIHZvbiBQdWJsaXNoZXJuIG1pdCBtaW5kZXN0ZW5zIDUwIG1pbyBpbiBTYWxlcy4gRGllcyBlbnRmZXJudCBuYXTDvHJsaWNoIGVpbmlnZXMgYW4gSW5mb3JtYXRpb24gYWxsZXJkaW5ncyBnZWh0IHNvbnN0IGVpbmlnZXMgYW4gw5xiZXJzaWNodGxpY2hrZWl0IHZlcmxvcmVuLiBadXPDpHR6bGljaCB3ZXJkZW4gZXJuZXV0IGRpZSBXb3J0ZSAiRW50ZXJ0YWlubWVudCIsICJJbnRlcmFjdGl2ZSIsICJHYW1lIiwgIkdhbWVzIiB1bmQgIlN0dWRpb3MiIGVudGZlcm50Lg0KYGBge3IgcGxvdChHZW5yZWJ5UHVibGlzaGVyKSwgaW5jbHVkZT1UUlVFLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lIA0KICBncm91cF9ieShQdWJsaXNoZXIsR2VucmUpICU+JSANCiAgc3VtbWFyaXplKHN1bShHbG9iYWxfU2FsZXMpKSAgJT4lDQpyZW5hbWUoDQogICAgR2xvYmFsX1NhbGVzID0gInN1bShHbG9iYWxfU2FsZXMpIg0KICAgICkgJT4lIGZpbHRlcihHbG9iYWxfU2FsZXM+NTApDQpncm91cGVkJEdsb2JhbF9TYWxlczwtYXNfdmVjdG9yKGdyb3VwZWQkR2xvYmFsX1NhbGVzKQ0KDQpncm91cGVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKGdyb3VwZWQkUHVibGlzaGVyLCAiRW50ZXJ0YWlubWVudCIpDQpncm91cGVkJFB1Ymxpc2hlciA8LXN0cl9yZW1vdmVfYWxsKGdyb3VwZWQkUHVibGlzaGVyLCAiSW50ZXJhY3RpdmUiKQ0KZ3JvdXBlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChncm91cGVkJFB1Ymxpc2hlciwgIlN0dWRpb3MiKQ0KZ3JvdXBlZCRQdWJsaXNoZXIgPC1zdHJfcmVtb3ZlX2FsbChncm91cGVkJFB1Ymxpc2hlciwgIkdhbWVzIikNCmdyb3VwZWQkUHVibGlzaGVyIDwtc3RyX3JlbW92ZV9hbGwoZ3JvdXBlZCRQdWJsaXNoZXIsICJHYW1lIikNCg0KYXggPC0gbGlzdCgNCiAgdGl0bGUgPSAiR2VucmUiDQopDQoNCmF5IDwtIGxpc3QoDQogIHRpdGxlID0gIlNhbGVzIg0KDQopDQoNCmdyb3VwZWQlPiUNCiAgcGxvdF9seSh4PX5mY3RfcmVvcmRlcihQdWJsaXNoZXIsR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpLA0KICAgICAgICAgICB5PX5HbG9iYWxfU2FsZXMsDQogICAgICAgICAgICB0eXBlPSdiYXInLA0KICAgICAgICAgICBjb2xvcj1+ZmN0X3Jlb3JkZXIoR2VucmUsR2xvYmFsX1NhbGVzLCAuZGVzYz0idHJ1ZSIpKSAgJT4lIA0KICBsYXlvdXQodGl0bGU9IlNhbGVzIGJ5IEdlbnJlIEJ5IFB1Ymxpc2hlciIsDQogICAgICAgICB4YXhpcyA9IGF4LA0KICAgICAgICAgeWF4aXMgPSBheSwNCiAgICAgICAgIGJhcm1vZGUgPSAnc3RhY2snDQogICAgICAgICApDQoNCg0KYGBgDQoNCg0KV2llIHNpZWh0IGVzIG1pdCBkZW4gUHJvIGtvcGYgU2FsZXMgR2xvYmFsIHVuZCBwcm8gUmVnaW9uIGF1cz8NCg0KYGBge3IgcGxvdChTYWxlc1BlckdhbWVQZXJQZXJzb25wZXJZZWFyKSwgaW5jbHVkZT1UUlVFLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J21hcmt1cCcsIH0NCmdyb3VwZWQgPC0gdmdzYWxlcyAgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGdyb3VwX2J5KFllYXIpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKGdyX3N1bSA9IHN1bShHbG9iYWxfU2FsZXMpLCBQb3B1bGF0aW9uID0gc3VtKFdvcmxkUG9wdWxhdGlvbiRZZWFyKSkgJT4lIGZpbHRlcihZZWFyIT0nTi9BJyklPiVmaWx0ZXIoWWVhciE9MjAyMCkgJT4lIGZpbHRlcihZZWFyIT0nMjAxNycpICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkNCg0Kdmlldyhncm91cGVkKQ0KZmlsdGVyZWQgPC0gZ3JvdXBlZCAlPiUgc2VsZWN0KFllYXIsZ3Jfc3VtKQ0KdmlldyhmaWx0ZXJlZCkNCg0KYGBg